package org.moda.table;


import cn.hutool.core.util.IdUtil;
import com.github.freva.asciitable.AsciiTable;
import org.moda.common.ArrayUtil;
import org.moda.common.Either;
import org.moda.common.Tuple2;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collector;

/**
 * @ClassName: Table
 * @Description: 表
 * @Author: xuanyang
 * @Date: 2024-11-02 19:58
 * @Version: 1.0
 **/
public class Table {
    public final String name;
    public final ColInfo[] colInfo;
    public final List<Col<?>[]> data;

    private Table(String name, ColInfo[] colInfo, List<Col<?>[]> data) {
        this.name = name;
        this.colInfo = colInfo;
        this.data = data;
    }

    public static Table of(String name, ColInfo[] colInfo, List<Col<?>[]> data) {
        return new Table(name, colInfo, data);
    }

    public int count() {
        return data.size();
    }



    public Table select(String... cols) {
        // 1. 构建新的表
        List<Either<String, Tuple2<Integer, ColInfo>>> queryCols = Arrays.stream(cols)
            .map(this::maybeColInfo)
            .toList();

        Optional<String> errorCol = queryCols.stream()
            .filter(Either::isLeft)
            .findFirst()
            .map(Either::getLeft);
        if (errorCol.isPresent()) {
            throw new IllegalArgumentException(errorCol.get());
        }

        List<ColInfo> newColInfo = queryCols.stream()
            .map(Either::getRight)
            .map(Tuple2::_2)
            .toList();

        List<Integer> colIndex = queryCols.stream()
            .map(Either::getRight)
            .map(Tuple2::_1).toList();

        List<Col<?>[]> newData = data.stream().map(x -> chooseCols(x, colIndex)).toList();

        return Table.of("tmp" + IdUtil.fastSimpleUUID(), newColInfo.toArray(ColInfo[]::new), newData);
    }

    public Table filter(String col, String value) {
        Either<String, Tuple2<Integer, ColInfo>> colEither = maybeColInfo(col);
        if (colEither.isLeft()) {
            throw new RuntimeException(colEither.getLeft());
        }
        Tuple2<Integer, ColInfo> colR = colEither.getRight();

        List<Col<?>[]> newData = data.stream().filter(x ->
            String.valueOf(x[colR._1()].value).equals(value)
        ).toList();

        return Table.of("tmp" + IdUtil.fastSimpleUUID(), colInfo, newData);
    }

    private static Col<?>[] chooseCols(Col<?>[] cols, List<Integer> colIndexes) {
        Col<?>[] newCols = new Col<?>[colIndexes.size()];
        for (int i = 0; i < colIndexes.size(); i++) {
            newCols[i] = cols[colIndexes.get(i)];
        }

        return newCols;
    }

    private Either<String, Tuple2<Integer, ColInfo>> maybeColInfo(String name) {
        for (int i = 0; i < colInfo.length; i++) {
            if (colInfo[i].name().equals(name)) {
                return Either.right(Tuple2.of(i, colInfo[i]));
            }
        }

        return Either.left("No such column " + name);
    }

    public void print() {
        System.out.println("table:" + name);
        String[] colNames = Arrays.stream(colInfo)
            .map(ColInfo::name)
            .toArray(String[]::new);
        String[][] dataStr = data.stream()
            .map(x ->
                Arrays.stream(x).map(Col::get).map(String::valueOf).toArray(String[]::new)
            ).toArray(String[][]::new);
        String tableAscii = AsciiTable.getTable(colNames, dataStr);
        System.out.println(tableAscii);
    }
}
